package com.lnsoft.cac.server.handle.codec;

import com.lnsoft.cac.server.util.Arrays16;
import com.lnsoft.cac.server.util.CRC16;
import io.netty.buffer.ByteBuf;
import lombok.extern.slf4j.Slf4j;

import java.util.List;

@Slf4j
public class I1FrameDecoder {
    public static void Decoder(ByteBuf byteBuf, List<Object> out ) {
        int readIndex = byteBuf.readerIndex();
        int writeIndex = byteBuf.writerIndex();
        while (true)
        {
            //continue 后需要重新寻找读索引位置
            readIndex = byteBuf.readerIndex();

            if (byteBuf.readableBytes() < 27) {    //  缓存字节不够最小完整的帧，跳过提取帧；
                return ;
            }

            //  检查帧头 确保开头总是帧头
            for (int i = readIndex; i < writeIndex - 1; i++) {
                int frameHead = byteBuf.getUnsignedShortLE(i);
                if (frameHead == 0x5AA5) {
                    break;
                }

                byteBuf.readBytes(i);      //丢掉脏数据 读索引下标位移
            }

            readIndex = byteBuf.readerIndex(); //重新复制读索引下标位置

            //  去除脏数据之后 缓存字节是否够完整帧
            if (byteBuf.readableBytes() < 27) {  //writeIndex - readIndex < 27
                return;
            }

            I1Frame i1Frame = new I1Frame();
            i1Frame.setMsgHead(0x5AA5);

            //  检查帧长
            int frameMessageLength = byteBuf.getUnsignedShortLE(readIndex + 2);
            if (frameMessageLength + 27 > (byteBuf.readableBytes())) {   //  如果帧长度(包括报文内容长度和帧格式字节长度)大于缓存的长度，到来的数据不够一帧，跳过当次的帧提取过程；

                log.info("缓存长度不够，需等待...");
                return;
            }
            i1Frame.setMsgLen(frameMessageLength);

            //  检查帧尾标志
            if ((byteBuf.getByte(readIndex + frameMessageLength + 26) & 0xFF) != 150) {
                log.debug("帧尾标志位异常");
                byteBuf.readByte();
                continue;
            }
            i1Frame.setMsgTail(0x96);
            //  检查校验码
            byte[] byCRCBody = new byte[frameMessageLength + 22];
            byteBuf.getBytes(readIndex + 2, byCRCBody);

            int nCRC16 = CRC16.GetCRC16(byCRCBody, byCRCBody.length);
            int frameCRC = byteBuf.getUnsignedShortLE(readIndex + frameMessageLength + 24);

            if (nCRC16 != frameCRC) {
                log.debug("error:   >>>>   nCRC16：{}, frameCRC: {}", nCRC16, frameCRC);
                byteBuf.readByte();
                continue;
            }
            i1Frame.setMsgCRC16(nCRC16);

            byte[] voltageMonitorID = new byte[17];
            byteBuf.getBytes(readIndex + 4, voltageMonitorID);
            i1Frame.setVoltageMonitorID(voltageMonitorID);

            i1Frame.setFrameType(byteBuf.getByte(readIndex + 21) & 0xFF);

            i1Frame.setMsgType(byteBuf.getByte(readIndex + 22) & 0xFF);

            i1Frame.setFrameSerialNum(byteBuf.getByte(readIndex + 23) & 0xFF);

            byte[] msgBody = new byte[frameMessageLength];
            byteBuf.getBytes(readIndex + 24, msgBody);
            i1Frame.setMsgBody(msgBody);

            //  提取帧
            byte[] f = new byte[frameMessageLength + 27];
            byteBuf.readBytes(f);
            log.info("<<< receive frame:{}",Arrays16.toString(f));
            out.add(i1Frame);

            if (byteBuf.writerIndex() - byteBuf.readerIndex() < 27) {    //  缓存字节不够最小完整的帧，跳过提取帧；
//                log.info("报文长度位：{}  , 小于最小帧长度，退出解析.", (byteBuf.writerIndex() - byteBuf.readerIndex()));
                return ;
            }
        }

    }
}
